package common.http;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.util.HashMap;
import java.util.Map;

import org.apache.http.Header;
import org.apache.http.util.ByteArrayBuffer;

public class HttpResponse {
	public static final int HTTP_STATUS_OK = 200;
	public static final int HTTP_STATUS_FAIL = 0;
	public static final int HTTP_STATUS_BAD_REQUEST = 400;
	public static final int HTTP_STATUS_UNAUTHORIZED = 401;
	public static final int HTTP_STATUS_FORBIDDEN = 403;
	public static final int HTTP_STATUS_NOT_FOUND = 404;
	public static final int HTTP_STATUS_INTERNAL_SERVER_ERROR 	= 500; 
	public static final int HTTP_STATUS_SERVICE_UNAVAILABLE 	= 503;
	
	public static final int HTTP_STATUS_NO_CONNECTION = 10000;
	public static final int HTTP_STATUS_ROAMING_CAN_NOT_3G = 10001;
	public static final int RESPONSE_NO_EXPIRE_TOKEN	= 10002;	// ��ū �ͽ����̾�...
	public static final int RESPONSE_SERVER_ERROR	= 10003;	// ���� ������ ����
	
	private static final int RESPONSE_READ_BUFFER_SIZE 	= 1024;
	private static final int RESPONSE_READ_BUFFER_SIZE_MAX 	= 64 * 1024;	//4MB
	
	private volatile static HttpResponse mInstance = null;
	
	private HttpResponse(){}
	
	public static HttpResponse getInstance(){
		if(mInstance == null) {
			synchronized ( HttpResponse.class ) {
				if(mInstance == null) {
					mInstance = new HttpResponse();
				}
			}
		}
		return mInstance;
	}
	
	
	/**
	 * Resonse를 받았을 경우 read한 후 SimpleHttpResponse로 변환하여 return 
	 * @param response
	 * @return
	 */	
	public SimpleHttpResponse getResponse(org.apache.http.HttpResponse response){
		if(response == null)
			return null;
		
		InputStream is = null;
    	try{
    		is = response.getEntity().getContent();
			byte[] responseBody = readBytesFromInputStream(is);
			is.close();
			//NateLog.d("HttpResponse", new String(responseBody));
			return new SimpleHttpResponse(response.getStatusLine().getStatusCode(), responseBody, response.getAllHeaders());
			
    	}catch(Exception e){
    		//NateLog.e(e.getMessage());
			int responseCode = response.getStatusLine().getStatusCode();
			
			if(responseCode != -1) {
				return new SimpleHttpResponse(responseCode, response.getEntity().toString());
			}
			
		} finally {
			try {
				if(is != null) { is.close(); }
				is = null;
			} catch (IOException e) { }
		}
    	return null;
	}
	
	public SimpleHttpResponse getResponse(HttpURLConnection connection){
		if(connection == null)
			return null;
		
		InputStream is = null;
		try {
			is = connection.getInputStream();
			byte[] responseBody = readBytesFromInputStream(is);
			is.close();
			
			HashMap<String, String> headers = new HashMap<String, String>();
			//for (int i = 0; true ; i++) {
			int i = 0;
			while(true){
				String headerName = connection.getHeaderFieldKey(i);
				String headerValue = connection.getHeaderField(i);
				if(headerName != null && headerValue != null){
					headers.put(headerName, headerValue);
					i++;
				}else{
					break;
				}
			}
			
			return new SimpleHttpResponse(connection.getResponseCode(), responseBody, headers);
		} catch (Exception e) {
			// 디버그일때만 출력하도록한다.
			e.printStackTrace();
		} finally {
			if( is != null){
				try{
					is.close();
					is = null;
				}catch (Exception e){
					// 디버그일때만 출력하도록한다.
					e.printStackTrace();
				}
			}
			
			if (connection != null){
				connection.disconnect();
			}			
		}
		
		return null;
	}
	
	/**
	 * 커넥션 자체가 없을때~
	 * @return
	 */
	public SimpleHttpResponse getResponseNetworkErrorResult() {
		return new SimpleHttpResponse(HttpResponse.HTTP_STATUS_NO_CONNECTION, "");
	}
	
	/**
	 * 네트웍이 로밍망일 경우
	 * @return
	 */
	public SimpleHttpResponse getResponseNetworkRoamingResult() {
		return new SimpleHttpResponse(HttpResponse.HTTP_STATUS_ROAMING_CAN_NOT_3G, "");
	}
		
	/**
	 * 서버측 오류
	 * @return
	 */
	public SimpleHttpResponse getResponseServerErrorResult() {
		return new SimpleHttpResponse(HttpResponse.RESPONSE_SERVER_ERROR, "");
	}
	
	
	/**
	 * Stream 읽기
	 * @param is
	 * @return
	 */
	private static byte[] readBytesFromInputStream(InputStream is) {
		try	{
			
			//BufferedReader br = new BufferedReader(new InputStreamReader(is, "UTF-8"));
			
    		// TODO : AsyncTask 안에서 버터스트림을 읽는 문제가 발생하여 
    		// ByteArrayBuffer 가 아니라 BufferedOutputStrem에 기록하여 문제 해결했다는 얘기가 있음. 확인 필요
			ByteArrayBuffer buffer = new ByteArrayBuffer(RESPONSE_READ_BUFFER_SIZE_MAX);
			byte[] bytes = new byte[RESPONSE_READ_BUFFER_SIZE];
			int bytesRead, startPos, length;
			boolean firstRead = true;
			while((bytesRead = is.read(bytes, 0, RESPONSE_READ_BUFFER_SIZE)) > 0){
				startPos = 0;
				length = bytesRead;
				if(firstRead){
					//remove first occurrence of '0xEF 0xBB 0xBF' (UTF-8 BOM)
					if(bytesRead >= 3 && (bytes[0] & 0xFF) == 0xEF && (bytes[1] & 0xFF) == 0xBB && (bytes[2] & 0xFF) == 0xBF){
						startPos += 3;
						length -= 3;
					}
					firstRead = false;
				}
				buffer.append(bytes, startPos, length);
			}
			return buffer.toByteArray();
		}catch(Exception e)	{
			//NateLog.e("HttpUtility.readBytesFromInputStream", e.toString());
		}
		
		return null;
	}
	
	/**
	 * Response 가공 클래스
	 *
	 */
	public class SimpleHttpResponse
	{
		private int httpStatusCode;
		private byte[] httpResponseBody;
		private Map<String, String> httpHeaders = null;
		
		public SimpleHttpResponse(int httpStatusCode, byte[] httpResponseBody, Header[] headers)
		{

			this(httpStatusCode, httpResponseBody);
			if(headers != null) {
				httpHeaders = new HashMap<String, String>();
				Header header = null;
				for(int i=0; i<headers.length; i++) {
					header = headers[i];
					httpHeaders.put(header.getName(), header.getValue());
				}
			}			
		}
		
		public SimpleHttpResponse(int httpStatusCode, byte[] httpResponseBody, HashMap<String, String> headers)
		{

			this(httpStatusCode, httpResponseBody);
			if(headers != null) {
				httpHeaders = headers;
			}			
		}
		
		public SimpleHttpResponse(int httpStatusCode, byte[] httpResponseBody)
		{
			this.httpStatusCode = httpStatusCode;
			this.httpResponseBody = httpResponseBody;
		}
		
		public SimpleHttpResponse(int httpStatusCode, String httpResponseBody)
		{
			this.httpStatusCode = httpStatusCode;
			this.httpResponseBody = httpResponseBody.getBytes();
		}


		public int getHttpStatusCode()
	    {
	    	return httpStatusCode;
	    }

		public byte[] getHttpResponseBody()
		{
			return httpResponseBody;
		}
		
		public boolean isBodyNull(){
			if (httpResponseBody == null)
			{
				return true;
			}
			return false;
		}

		public String getHttpResponseBodyAsString()
	    {
			if (httpResponseBody != null)
			{
				return new String(httpResponseBody);
			}
			
			return null;
	    }

		public ByteArrayInputStream getHttpResponseBodyAsInputStream()
		{
			if (httpResponseBody != null)
			{
				return new ByteArrayInputStream(httpResponseBody);
			}
			
			return null;
		}

		public Map<String, String> getHeaders()
		{
			return httpHeaders;
		}

	}
}
